﻿
using Xacml.Core;
using Xacml.Core.Interfaces;
using Xacml.Core.Policy;
using Xacml.Core.Runtime;
using System;
using System.Collections;
using System.IO;
using System.Security.Permissions;
using System.Xml;

namespace Xacml.Core.Extensions
{
  public class DefaultPolicyRepository : IPolicyRepository
  {
    private Hashtable _policies = new Hashtable();
    private Hashtable _policySets = new Hashtable();

    [PermissionSet(SecurityAction.Demand, XML = "<PermissionSet class=\"System.Security.PermissionSet\"\r\n               version=\"1\">\r\n   <IPermission class=\"System.Security.Permissions.ReflectionPermission, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\r\n                version=\"1\"\r\n                Flags=\"TypeInformation\"/>\r\n</PermissionSet>\r\n")]
    public void Init(XmlNode configNode)
    {
      foreach (XmlNode xmlNode in configNode.ChildNodes)
      {
        if (xmlNode.Name == "PolicySet")
          this._policySets.Add((object) xmlNode.Attributes["PolicySetId"].Value, (object) new PolicyDocument((XmlReader) new XmlTextReader((TextReader) new StreamReader(xmlNode.Attributes["FilePath"].Value)), (XacmlVersion) Enum.Parse(typeof (XacmlVersion), xmlNode.Attributes["xacmlVersion"].Value, false)));
        else if (xmlNode.Name == "Policy")
          this._policies.Add((object) xmlNode.Attributes["PolicyId"].Value, (object) new PolicyDocument((XmlReader) new XmlTextReader((TextReader) new StreamReader(xmlNode.Attributes["FilePath"].Value)), (XacmlVersion) Enum.Parse(typeof (XacmlVersion), xmlNode.Attributes["xacmlVersion"].Value, false)));
      }
    }

    public PolicyElement GetPolicy(PolicyIdReferenceElement policyReference)
    {
      PolicyDocument policyDocument = this._policies[(object) policyReference.PolicyId] as PolicyDocument;
      if (policyDocument != null)
        return (PolicyElement) policyDocument.Policy;
      return (PolicyElement) null;
    }

    public PolicySetElement GetPolicySet(PolicySetIdReferenceElement policySetReference)
    {
      PolicyDocument policyDocument = this._policySets[(object) policySetReference.PolicySetId] as PolicyDocument;
      if (policyDocument != null)
        return (PolicySetElement) policyDocument.PolicySet;
      return (PolicySetElement) null;
    }

    public PolicyDocument Match(EvaluationContext context)
    {
      PolicyDocument policyDocument1 = (PolicyDocument) null;
      foreach (PolicyDocument policyDocument2 in (IEnumerable) this._policySets.Values)
      {
        if (new PolicySet(context.Engine, (PolicySetElement) policyDocument2.PolicySet).Match(new EvaluationContext(context.Engine, policyDocument2, context.ContextDocument)) == TargetEvaluationValue.Match)
        {
          if (policyDocument1 != null)
            throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_duplicated_policy_in_repository]);
          policyDocument1 = policyDocument2;
        }
      }
      foreach (PolicyDocument policyDocument2 in (IEnumerable) this._policies.Values)
      {
		  if (new Xacml.Core.Runtime.Policy(context.Engine, (PolicyElement) policyDocument2.Policy).Match(new EvaluationContext(context.Engine, policyDocument2, context.ContextDocument)) == TargetEvaluationValue.Match)
        {
          if (policyDocument1 != null)
            throw new EvaluationException(Resource.ResourceManager[Resource.MessageKey.exc_duplicated_policy_in_repository]);
          policyDocument1 = policyDocument2;
        }
      }
      return policyDocument1;
    }
  }
}
